package com.black.template.service.handler.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.black.template.excelToPdf.Excel2Pdf;
import com.black.template.excelToPdf.ExcelObject;
import com.black.template.service.biz.TemplateService;
import com.black.template.service.handler.TemplateHandlerService;
import com.black.template.vo.DocumentTemplateVo;
import com.black.template.vo.FileVo;
import com.black.template.vo.TemplateVo;
import com.fasterxml.jackson.databind.util.JSONPObject;
import org.apache.commons.codec.binary.Base64;
import org.jxls.common.Context;
import org.jxls.util.JxlsHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class TemplateHandlerServiceImpl implements TemplateHandlerService {

    @Autowired
    TemplateService templateService;


    @Override
    public String generateDocumentData(DocumentTemplateVo documentTemplateVo) throws Exception {
        TemplateVo templateVo = templateService.getTemplateVoById(documentTemplateVo.getTemplateId());
       // fileDataHandler(documentTemplateVo);
        if ("Excel".equals(templateVo.getTemplate().getTemplateType())){
            ByteArrayOutputStream bass = new ByteArrayOutputStream();
            generateExcelDocument(templateVo.getInputStream(),bass, documentTemplateVo.getFillData());
            ByteArrayInputStream swapStream = new ByteArrayInputStream(bass.toByteArray());
            ExcelObject excelObject = new ExcelObject(swapStream);
            ByteArrayOutputStream swapStream2 = new ByteArrayOutputStream();
            Excel2Pdf excel2Pdf = new Excel2Pdf(excelObject, swapStream2);
            excel2Pdf.convert();
            return new String(Base64.encodeBase64(swapStream2.toByteArray()));
        }
        return null;
    }

    @Override
    public DocumentTemplateVo fileDataHandler(DocumentTemplateVo documentTemplateVo){
        if (documentTemplateVo.getFileData()==null||documentTemplateVo.getFileData().size()==0){
         return documentTemplateVo;
        }
        Map<String, Object> fillData = documentTemplateVo.getFillData();
        Map<String,Map<String,Object>> arrayKeyMap = new HashMap<>();
        int index = 0;
        for (FileVo fileVo : documentTemplateVo.getFileData()){
            if(arrayKeyMap.get(fileVo.getKey())!=null){
                arrayKeyMap.get(fileVo.getKey()).put("isArray",true);
            }else{
                Map<String,Object> keyInfo = new HashMap<>(2);
                keyInfo.put("startIndex",index);
                keyInfo.put("isArray",false);
                arrayKeyMap.put(fileVo.getKey(),keyInfo);
            }
            index ++;
        }
        index = 0;
        for (FileVo fileVo : documentTemplateVo.getFileData()){
            String[] keys = fileVo.getKey().split("\\.");
            Map<String,Object> temp = null;
            List<Object> arrayTemp = null;
            if (keys.length==1){
                if ((Boolean) arrayKeyMap.get(fileVo.getKey()).get("isArray")){
                    if (fillData.get(fileVo.getKey())==null){
                        arrayTemp = new ArrayList<>();
                        arrayTemp.add(fileVo.getData());
                        fillData.put(fileVo.getKey(),arrayTemp);
                    }else{
                        arrayTemp = (List<Object>) fillData.get(fileVo.getKey());
                        arrayTemp.add(fileVo.getData());
                    }
                }else{
                    fillData.put(keys[0],fileVo.getData());
                }
            }else {
                int startIndex = (int) arrayKeyMap.get(fileVo.getKey()).get("startIndex");
                for (int i=0;i<keys.length;i++){
                    if (i==keys.length-1){
                        if (temp!=null){
                            temp.put(keys[i],fileVo.getData());
                        }
                        else if (arrayTemp!=null){
                            if (arrayTemp.size()>(index-startIndex)){
                                temp = (Map<String, Object>) arrayTemp.get(index-startIndex);
                                temp.put(keys[i],fileVo.getData());
                            }else{
                                temp = new HashMap<>();
                                temp.put(keys[i],fileVo.getData());
                                arrayTemp.add(temp);
                            }
                        }
                    }else {
                         if (temp==null && arrayTemp==null){
                             if (fillData.get(keys[i])==null){
                                 if ((Boolean) arrayKeyMap.get(fileVo.getKey()).get("isArray")&&i==keys.length-2){
                                    arrayTemp = new ArrayList<>();
                                    fillData.put(keys[i],arrayTemp);
                                 }else {
                                     temp = new HashMap<>();
                                     fillData.put(keys[i],temp);
                                 }
                             }else {
                                 if (index > startIndex) {
                                     if(fillData.get(keys[i]) instanceof Map){
                                         temp = (Map<String, Object>) fillData.get(keys[i]);
                                     }
                                     else if(fillData.get(keys[i]) instanceof List){
                                         arrayTemp = (JSONArray) fillData.get(keys[i]);
                                     }
                                 } else {
                                     if(fillData.get(keys[i]) instanceof Map){
                                         temp = (Map<String, Object>) fillData.get(keys[i]);
                                     }else if(fillData.get(keys[i]) instanceof List){
                                         arrayTemp = (List<Object>) fillData.get(keys[i]);
                                     }else if (fillData.get(keys[i]) instanceof String){
                                         String jsonData = fillData.get(keys[i]).toString();
                                          if (jsonData.startsWith("[")) {
                                             arrayTemp = JSONObject.parseArray(jsonData);
                                             fillData.put(keys[i], arrayTemp);
                                         } else {
                                             temp = JSONObject.parseObject(jsonData);
                                             fillData.put(keys[i], temp);
                                         }
                                     }
                                 }
                             }
                         }else{
                             if (temp!=null){
                                 Map<String,Object> map;
                                 if (temp.get(keys[i])==null){
                                     if ((Boolean) arrayKeyMap.get(fileVo.getKey()).get("isArray")&&i==keys.length-2){
                                         arrayTemp = new ArrayList<>();
                                         temp.put(keys[i],arrayTemp);
                                         temp = null;
                                     }else{
                                         map = new HashMap<>();
                                         temp.put(keys[i],map);
                                         temp = map;
                                     }
                                 }else{
                                     if (temp.get(keys[i]) instanceof String){
                                         String jsonData = temp.get(keys[i]).toString();
                                         map = JSONObject.parseObject(jsonData);
                                         temp.put(keys[i],map);
                                         temp = map;
                                     }else if (temp.get(keys[i]) instanceof Map){
                                         temp = (Map<String, Object>) temp.get(keys[i]);
                                     }else if (temp.get(keys[i]) instanceof List){
                                         arrayTemp = (List<Object>) temp.get(keys[i]);
                                         temp = null;
                                     }
                                 }
                             }
                         }
                    }
                }
            }
            index ++;
        }
        return documentTemplateVo;
    }

    private void generateExcelDocument(InputStream is, OutputStream os, Map<String,Object> fillData) throws IOException {
        Context context = new Context(fillData);
        JxlsHelper.getInstance().processTemplate(is, os, context);
    }
}
